﻿
/**
* 命名空间: Assets.Scripts.TDBehavior.Editor
*
* 功 能： N/A
* 类 名： NodeBaseEditor
*
* Ver 变更日期 负责人 变更内容
* ───────────────────────────────────
* V0.01 2019/12/12 16:59:48  
*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;


namespace Game.TDBehaviorTree
{
    [Serializable]
    public class NodeEditorFile
    {
        public List<NodeValue> nodes;
        public List<Connection> connections;
    }


    public enum OperationType
    {
        CraetNew,
        Load,
        Save,
        None,
    }

   
    public class NodeBaseEditor : EditorWindow
    {

        public   NodeEditorFile m_NodeFile;
        private NodeEditorFile m_CurrentFile;

        private  GUIStyle nodeStyle;
        private  GUIStyle selectedNodeStyle;
        private  GUIStyle inPointStyle;
        private  GUIStyle outPointStyle;

        private  TDConnectionPoint selectedInPoint;
        private  TDConnectionPoint selectedOutPoint;

        private  GameObject m_SelectObj;

        private Vector2 offset;
        private Vector2 drag;

        private string fileName;
        private OperationType m_OperationType=OperationType.None;
        private string m_LoadFileName;

      
       [MenuItem("Tools/Node Editor")]
        private static void OpenWindow()
        {
            NodeBaseEditor window = GetWindow<NodeBaseEditor>();
            window.titleContent = new GUIContent("TDBehaviorNode");
        }

        private void OnEnable()
        {

            nodeStyle = new GUIStyle();
            nodeStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/node0.png") as Texture2D;
            nodeStyle.border = new RectOffset(12, 12, 12, 12);

            selectedNodeStyle = new GUIStyle();
            selectedNodeStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/node0 on.png") as Texture2D;
            selectedNodeStyle.border = new RectOffset(12, 12, 12, 12);

            inPointStyle = new GUIStyle();
            inPointStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn act.png") as Texture2D;
            inPointStyle.active.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn onact.png") as Texture2D;
            inPointStyle.border = new RectOffset(4, 4, 12, 12);

            outPointStyle = new GUIStyle();
            outPointStyle.normal.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn act.png") as Texture2D;
            outPointStyle.active.background = EditorGUIUtility.Load("builtin skins/darkskin/images/btn onact.png") as Texture2D;
            outPointStyle.border = new RectOffset(4, 4, 12, 12);
        }

       

        private void OnGUI()
        {
            DrawGrid(20, 0.2f, Color.gray);
            DrawGrid(100, 0.4f, Color.gray);

            if(GUI.Button(new Rect(0, 0, 70, 20), "创建新文件"))
            {
                m_OperationType = OperationType.CraetNew;
                if (m_NodeFile == null || m_NodeFile.nodes==null)
                {
                    m_NodeFile = new NodeEditorFile();
                }
                else
                {
                    //进行提示 
                    if (EditorUtility.DisplayDialog("警告", "当前有文件正在使用，是否重新建立新的或者使用旧的?", "建立新的", "使用旧文件"))
                    {
                        m_NodeFile = new NodeEditorFile();
                    }
                    else
                    {
                       
                    }
                }
            


        }
            if (GUI.Button(new Rect(70, 0, 60, 20), "加载文件"))
            {
                m_OperationType = OperationType.Load;
                string path = EditorUtility.OpenFilePanel("选择文件", UnityEngine.Application.dataPath + "/BehaviorData", "json");

                if (path != string.Empty)
                {
                    var file = File.ReadAllText(path);
                    FileStream _fileStream = File.OpenRead(path);
                    m_LoadFileName = _fileStream.Name;
                    _fileStream.Close();

                    m_NodeFile = null;
                    var _loadfile = JsonUtility.FromJson<NodeEditorFile>(file);
                    for (int i = 0; i < _loadfile.nodes.Count; i++)
                    {
                        _loadfile.nodes[i].OnDeRealize(_loadfile.nodes, nodeStyle, selectedNodeStyle, inPointStyle, outPointStyle, OnClickInPoint, OnClickOutPoint, OnClickRemoveNode, SetRootNode);
                    }

                    for (int i = 0; i < _loadfile.connections.Count; i++)
                    {
                        _loadfile.connections[i].DeSerizable(_loadfile.nodes, OnClickRemoveConnection);
                    }
                    m_NodeFile = _loadfile;

                }

                foreach (var item in m_NodeFile.nodes)
                {
                    item.m_NodeBase.DeRializable(item);
                }

            }
            if (GUI.Button(new Rect(130, 0, 60, 20), "保存文件"))
            {
               
                m_OperationType = OperationType.Save;
            }
            if (GUI.changed) Repaint();
            switch (m_OperationType)
            {
                case OperationType.CraetNew:
                    m_SelectObj = (GameObject)EditorGUI.ObjectField(new Rect(10, 30, 150, 30), m_SelectObj, typeof(GameObject),true);
                    if (GUI.Button(new Rect(10, 80, 100, 30), "测试"))
                    {
                        if (m_SelectObj != null)
                        {
                            //必须在运行中进行
                            NodeValue rootNode = null;
                            for (int i = 0; i < m_NodeFile.nodes.Count; i++)
                            {
                                if (m_NodeFile.nodes[i].m_IsRoot)
                                {
                                    rootNode = m_NodeFile.nodes[i];
                                    break;
                                }
                            }
                            if (rootNode != null)
                            {
                                Debug.Log("正在测试");
                                rootNode.m_NodeBase.Agent = m_SelectObj;
                                TDBehaviorSystem.Instance.m_CurrentNode = rootNode.m_NodeBase;
                            }
                        }
                    }
                    break;
                case OperationType.Load:
                  EditorGUI.LabelField(new Rect(10, 30, 350, 30),"加载文件名字:"+m_LoadFileName);
                    break;
                case OperationType.Save:
                    GUI.Label(new Rect(10, 50, 60, 20), "保存Id填写");
                    fileName = GUI.TextField(new Rect(10, 70, 100, 20), fileName);
                    if (GUI.Button(new Rect(10, 120, 100, 30), "保存信息"))
                    {
                        if(m_NodeFile==null ||m_NodeFile.nodes==null || m_NodeFile.nodes.Count <= 0)
                        {
                            ShowNotification(new GUIContent("没有文件能够进行保存，请重试"));
                        }
                        else
                        {
                            SavaData();
                        }
                      
                    }
                    break;
            }
            if (m_NodeFile != null)
            {
                DrawNodes();
                DrawConnections();

                DrawConnectionLine(Event.current);

                ProcessNodeEvents(Event.current);
                ProcessEvents(Event.current);
            }
          
        }


        //保存信息
        private void SavaData()
        {
            if (m_NodeFile.nodes != null)
            {
              

                NodeValue rootNode = null;
                for (int i = 0; i < m_NodeFile.nodes.Count; i++)
                {
                    if (m_NodeFile.nodes[i].m_IsCombineNode)
                    {
                        if (m_NodeFile.nodes[i].SortChildNode())
                        {
                            ShowNotification(new GUIContent("节点序列号出错，请检查"));
                            return;
                        }
                    }

                    if (m_NodeFile.nodes[i].m_IsRoot)
                    {
                        rootNode = m_NodeFile.nodes[i];
                        break;
                    }
                }
                if (rootNode != null)
                {
                    if (fileName == string.Empty)
                    {
                        ShowNotification(new GUIContent("fill name is null,plaease check!!!"));
                    }
                    else
                    {
                        JsonDataParser.WriteJson(rootNode.m_NodeBase, string.Format("{0}.json", fileName));

                        string _path = UnityEngine.Application.dataPath + "/BehaviorData";
                        string filePath = _path + "/" + fileName+".json";
                        if (!Directory.Exists(_path))
                            Directory.CreateDirectory(_path);
                        if (File.Exists(filePath))
                            File.Delete(filePath);

                        string values = JsonUtility.ToJson(m_NodeFile);
                        FileStream file = new FileStream(filePath, FileMode.Create);
                        byte[] bts = System.Text.Encoding.UTF8.GetBytes(values);
                        file.Write(bts, 0, bts.Length);
                        if (file != null)
                        {
                            file.Close();
                        }

                        UnityEditor.AssetDatabase.Refresh();
                        ShowNotification(new GUIContent("save success"));
                    }

                 
                }
                else
                {
                    ShowNotification(new GUIContent("root node is null"));
                }


              

              
            }
        }

        private void DrawGrid(float gridSpacing, float gridOpacity, Color gridColor)
        {
            int widthDivs = Mathf.CeilToInt(position.width / gridSpacing);
            int heightDivs = Mathf.CeilToInt(position.height / gridSpacing);

            Handles.BeginGUI();
            Handles.color = new Color(gridColor.r, gridColor.g, gridColor.b, gridOpacity);

            offset += drag * 0.5f;
            Vector3 newOffset = new Vector3(offset.x % gridSpacing, offset.y % gridSpacing, 0);

            for (int i = 0; i < widthDivs; i++)
            {
                Handles.DrawLine(new Vector3(gridSpacing * i, -gridSpacing, 0) + newOffset, new Vector3(gridSpacing * i, position.height, 0f) + newOffset);
            }

            for (int j = 0; j < heightDivs; j++)
            {
                Handles.DrawLine(new Vector3(-gridSpacing, gridSpacing * j, 0) + newOffset, new Vector3(position.width, gridSpacing * j, 0f) + newOffset);
            }

            Handles.color = Color.white;
            Handles.EndGUI();
        }

        private void DrawNodes()
        {
            if (m_NodeFile.nodes != null)
            {
                for (int i = 0; i < m_NodeFile.nodes.Count; i++)
                {
                    m_NodeFile.nodes[i].Draw();
                }
            }
        }

        private void DrawConnections()
        {
            if (m_NodeFile.connections != null)
            {
                for (int i = 0; i < m_NodeFile.connections.Count; i++)
                {
                    m_NodeFile.connections[i].Draw();
                }
            }
        }

        private void ProcessEvents(Event e)
        {
            drag = Vector2.zero;

            switch (e.type)
            {
                case EventType.MouseDown:
                    if (e.button == 0)
                    {
                        ClearConnectionSelection();
                    }

                    if (e.button == 1)
                    {
                        ProcessContextMenu(e.mousePosition);
                    }
                    break;

                case EventType.MouseDrag:
                    if (e.button == 0)
                    {
                        OnDrag(e.delta);
                    }
                    break;
            }
        }

        private void ProcessNodeEvents(Event e)
        {
            if (m_NodeFile.nodes != null)
            {
                for (int i = m_NodeFile.nodes.Count - 1; i >= 0; i--)
                {
                    bool guiChanged = m_NodeFile.nodes[i].ProcessEvents(e);

                    if (guiChanged)
                    {
                        GUI.changed = true;
                    }
                }
            }
        }

        private void DrawConnectionLine(Event e)
        {
            if (selectedInPoint != null && selectedOutPoint == null)
            {
                Handles.DrawBezier(
                    selectedInPoint.Rect.center,
                    e.mousePosition,
                    selectedInPoint.Rect.center + Vector2.left * 50f,
                    e.mousePosition - Vector2.left * 50f,
                    Color.white,
                    null,
                    2f
                );

                GUI.changed = true;
            }

            if (selectedOutPoint != null && selectedInPoint == null)
            {
                Handles.DrawBezier(
                    selectedOutPoint.Rect.center,
                    e.mousePosition,
                    selectedOutPoint.Rect.center - Vector2.left * 50f,
                    e.mousePosition + Vector2.left * 50f,
                    Color.white,
                    null,
                    2f
                );

                GUI.changed = true;
            }
        }

        private void ProcessContextMenu(Vector2 mousePosition)
        {
            GenericMenu genericMenu = new GenericMenu();
            genericMenu.AddItem(new GUIContent("选择节点"), false, () => OnClickAddNode(mousePosition, NodeType.Select));
            genericMenu.AddItem(new GUIContent("顺序节点"), false, () => OnClickAddNode(mousePosition, NodeType.Sequence));
            genericMenu.AddItem(new GUIContent("随机节点"), false, () => OnClickAddNode(mousePosition, NodeType.Random));
            genericMenu.AddItem(new GUIContent("并行节点"), false, () => OnClickAddNode(mousePosition, NodeType.Parallel));
            genericMenu.AddItem(new GUIContent("条件节点"), false, /*() => OnClickAddNode(mousePosition)*/null);
            genericMenu.AddItem(new GUIContent("装饰节点"), false,/* () => OnClickAddNode(mousePosition)*/null);

            var actionTypes = EnumberHelper.EnumToList<ActionNodeType>();
            for (int i = 0; i < actionTypes.Count; i++)
            {
                ActionNodeType _actionNodeType = (ActionNodeType)actionTypes[i].EnumValue;
                genericMenu.AddItem(new GUIContent("行为节点/" + actionTypes[i].Desction), false, () => OnClickAddNode(mousePosition, NodeType.Action, _actionNodeType));
            }


            genericMenu.ShowAsContext();
        }

        private void OnDrag(Vector2 delta)
        {
            drag = delta;

            if (m_NodeFile.nodes != null)
            {
                for (int i = 0; i < m_NodeFile.nodes.Count; i++)
                {
                    m_NodeFile.nodes[i].Drag(delta);
                }
            }

            GUI.changed = true;
        }

        private void OnClickAddNode(Vector2 mousePosition, NodeType _nodeType, ActionNodeType _actionNodeType = ActionNodeType.Log,
            ConditionNodeType _conditionNodeType = ConditionNodeType.None, DecorateNodeType _decorateNodeType = DecorateNodeType.None)
        {
            if (m_NodeFile.nodes == null)
            {
                m_NodeFile.nodes = new List<NodeValue>();
            }

            m_NodeFile.nodes.Add(new NodeValue(m_NodeFile.nodes.Count,m_NodeFile.nodes,_nodeType, _actionNodeType, _conditionNodeType, _decorateNodeType, mousePosition, 150, 270,
                nodeStyle, selectedNodeStyle, inPointStyle, outPointStyle, OnClickInPoint,
                OnClickOutPoint, OnClickRemoveNode, SetRootNode));
        }


        //左侧按钮 InPoint
        private void OnClickInPoint(TDConnectionPoint inPoint)
        {
            selectedInPoint = inPoint;
            if (selectedOutPoint != null)
            {
                if (selectedOutPoint.Node != selectedInPoint.Node)
                {
                    CreateConnection();
                    ClearConnectionSelection();
                }
                else
                {
                    ClearConnectionSelection();
                }
            }
        }

        //右侧按钮OutPoint

        private void OnClickOutPoint(TDConnectionPoint outPoint)
        {
            selectedOutPoint = outPoint;

            if (selectedInPoint != null)
            {
                if (selectedOutPoint.Node != selectedInPoint.Node)
                {
                    CreateConnection();
                    ClearConnectionSelection();
                }
                else
                {
                    ClearConnectionSelection();
                }
            }
        }

        //移除节点
        private void OnClickRemoveNode(NodeValue node)
        {
            if (m_NodeFile.connections != null)
            {

                for (int i = 0; i < m_NodeFile.connections.Count; i++)
                {
                    if (m_NodeFile.connections[i].inPoint.Node == node)
                    {
                        m_NodeFile.connections[i].outPoint.Node.RemoveChildNode(node);
                    }
                }

                //移除需要对子节点进行移除
                if (node.m_InPoint != null)
                {
                     node.m_InPoint.Node.RemoveChildNode(node);
                }


                List<Connection> connectionsToRemove = new List<Connection>();

                for (int i = 0; i < m_NodeFile.connections.Count; i++)
                {
                    if (m_NodeFile.connections[i].inPoint == node.m_InPoint || m_NodeFile.connections[i].outPoint == node.m_OutPoint)
                    {
                        connectionsToRemove.Add(m_NodeFile.connections[i]);
                    }
                }

                for (int i = 0; i < connectionsToRemove.Count; i++)
                {
                    m_NodeFile.connections.Remove(connectionsToRemove[i]);
                }

                connectionsToRemove = null;

            }

            m_NodeFile.nodes.Remove(node);
        }

        private void OnClickRemoveConnection(Connection connection)
        {
            m_NodeFile.connections.Remove(connection);
        }


        //创建两个Node连接
        private void CreateConnection()
        {
            if (m_NodeFile.connections == null)
            {
                m_NodeFile.connections = new List<Connection>();
            }

            //先要判断 节点是否能够延伸  
            //组合节点能够延伸
            //但是叶子节点是不能够延伸 ActionNode ConditionNode DecorateNode 不能
            //还要看是否是根节点进行判断

            NodeType selecIntNodeType = selectedInPoint.Node.m_NodeType;  //连线开始节点
            NodeType selectOutNodeType = selectedOutPoint.Node.m_NodeType;  //连线结束节点



            for (int i = 0; i < m_NodeFile.connections.Count; i++)
            {
                if (m_NodeFile.connections[i].inPoint.Node == selectedOutPoint.Node && m_NodeFile.connections[i].outPoint.Node == selectedInPoint.Node)
                {
                    ShowNotification(new GUIContent("error,行为节点不能成环!!!"));
                    return;
                }

                if (m_NodeFile.connections[i].inPoint == selectedInPoint && m_NodeFile.connections[i].outPoint == selectedOutPoint)
                {
                    ShowNotification(new GUIContent("error,已经存在该连接!!!"));
                    return;
                }
            }


            //同个Node节点In只能连接一个Out但是Out能同时连接多个In
            for (int i = 0; i < m_NodeFile.connections.Count; i++)
            {
                if (m_NodeFile.connections[i].inPoint == selectedInPoint)
                {
                    ShowNotification(new GUIContent("error,一个节点只能拥有一个父亲节点!!!"));
                    return;
                }
            }



            if (selectedInPoint.Node.m_IsCombineNode)
            {
                //Inpoint 如果是root 节点并且还是组合节点话，Point按钮则隐藏了，不需要考虑此项
                //无论Out节点是什么类型
                if (selectedOutPoint.Node.m_IsCombineNode)
                {
                    AddConecttion(selectedInPoint, selectedOutPoint);
                }
                else
                {
                    //加强判断了下 ，虽然如果是叶子节点话，Out节点按钮是屏蔽状态
                    ShowNotification(new GUIContent("error,组合节点是不能连接在叶子节点下!!!"));

                }
            }
            else
            {



                if (selectedOutPoint.Node.m_IsCombineNode)
                {
                    AddConecttion(selectedInPoint, selectedOutPoint);
                }
                else
                {
                    ShowNotification(new GUIContent("error,叶子节点是不能连接在叶子节点下!!!"));

                }

            }

        }


        //增加连接
        private void AddConecttion(TDConnectionPoint inPoint, TDConnectionPoint outPoint)
        {
            m_NodeFile.connections.Add(new Connection(inPoint, outPoint, OnClickRemoveConnection));
            if (outPoint.Node != null)
            {
                outPoint.Node.AddChildNode(inPoint.Node);
            }
        }


        //清除节点连接
        private void ClearConnectionSelection()
        {
            selectedInPoint = null;
            selectedOutPoint = null;
        }


        //设置主节点
        private void SetRootNode(NodeValue _node)
        {
            foreach (var item in m_NodeFile.nodes)
            {
                if (_node == item)
                    item.m_IsRoot = true;
                else
                    item.m_IsRoot = false;
            }

        }

    }
}
